package com.stanwind.sgit.exec;

import com.stanwind.sgit.exception.GitException;
import com.stanwind.sgit.exception.RepoNotExistException;
import com.stanwind.sgit.util.ShellUtil;
import com.stanwind.sgit.util.StringUtils;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * AbsGitOperation git shell执行模板
 *
 * @author : Stan
 * @version : 1.0
 * @date :  2019-11-29 10:45
 **/
public abstract class AbsGitOperation {

    private static final Logger logger = LoggerFactory.getLogger(AbsGitOperation.class);

    public static final String STR_GIT_RES_FATAL_NOT_GIT_REPO = "not a git repository";


    /**
     * 返回console输出内容 处理
     * @param msg
     * @return
     * @throws GitException
     */
    protected abstract boolean processExecLog(String msg) throws GitException;

    /**
     * 执行git shell
     * @param localRepo
     * @return
     * @throws GitException
     */
    public abstract boolean exec(File localRepo) throws GitException;

    protected String convertCmdsToCmd(String[] cmd) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < cmd.length; i++) {
            sb.append(cmd[i]).append(" ");
        }

        return sb.toString();
    }

    /**
     * 执行git shell  线程读取console输出
     * @param cmd
     * @param localRepo
     * @return
     * @throws GitException
     */
    protected boolean execWithLogThread(String[] cmd, File localRepo) throws GitException {
        long cur = System.currentTimeMillis();
        logger.info("exec [{} {}] start {}ms", cmd[0], cmd[1], cur);
        if (localRepo == null || localRepo.getAbsolutePath().isEmpty()) {
            logger.error("git repo not exist");
            throw new RepoNotExistException();
        }

        Process process = null;
        int code = 0;
        ReadStreamThread tInfo = null;
        ReadStreamThread tError = null;
        try {
            process = Runtime.getRuntime().exec(cmd, new String[]{}, localRepo);
            tInfo  = new ReadStreamThread(process.getInputStream());
            tError = new ReadStreamThread(process.getErrorStream());
            tInfo.start();
            tError.start();
            code = process.waitFor();
        } catch (IOException | InterruptedException e) {
            logger.error("git command execute error.");
            throw new GitException(e);
        } finally {
            if (tInfo != null) {
                tInfo.interrupt();
            }

            if (tError!= null) {
                tError.interrupt();
            }
        }

        if (code != 0) {
            String errorText = tError.getMsg();
            if (errorText.contains(STR_GIT_RES_FATAL_NOT_GIT_REPO)) {
                logger.error("git repo not exist: {}", localRepo.getAbsolutePath());
                throw new RepoNotExistException();
            }

            StringBuilder stringBuilder = new StringBuilder().append("git pull path:")
                    .append(localRepo.getAbsolutePath())
                    .append("\n").append(errorText).append("\n");

            logger.info("exec [{} {}] error {}ms", cmd[0], cmd[1], System.currentTimeMillis() - cur);
            throw new GitException(stringBuilder.toString());
        } else {
            boolean res = processExecLog(tInfo.getMsg());
            logger.info("exec [{} {}] cost {}ms", cmd[0], cmd[1], System.currentTimeMillis() - cur);
            return res;
        }
    }

    /**
     * 执行git shell 同步读取console输出
     * @param cmd
     * @param localRepo
     * @return
     * @throws GitException
     */
    protected boolean exec(String[] cmd, File localRepo) throws GitException {
        long cur = System.currentTimeMillis();
        logger.info("exec [{} {}] start {}ms", cmd[0], cmd[1], cur);
        if (localRepo == null || localRepo.getAbsolutePath().isEmpty()) {
            logger.error("git repo not exist");
            throw new RepoNotExistException();
        }

        Process process = null;
        int code = 0;

        try {
            process = Runtime.getRuntime().exec(cmd, new String[]{}, localRepo);
            code = process.waitFor();
        } catch (IOException | InterruptedException e) {
            logger.error("git command execute error.");
            throw new GitException(e);
        }

        if (code != 0) {
            String errorText = null;
            try {
                errorText = StringUtils.readFromInputStream(process.getErrorStream(), ShellUtil.SHELL_CHARSET);
            } catch (IOException e) {
                logger.error("git command execute error.");
                throw new GitException(e);
            }

            if (errorText.contains(STR_GIT_RES_FATAL_NOT_GIT_REPO)) {
                logger.error("git repo not exist: {}", localRepo.getAbsolutePath());
                throw new RepoNotExistException();
            }

            StringBuilder stringBuilder = new StringBuilder().append("git pull path:")
                    .append(localRepo.getAbsolutePath())
                    .append("\n").append(errorText).append("\n");

            throw new GitException(stringBuilder.toString());
        } else {
            String msg = "";
            try {
                msg = StringUtils.readFromInputStream(process.getInputStream());
            } catch (IOException e) {
                logger.error("git command execute success, but error occurred when read log.");
                throw new GitException(e);
            }

            boolean res = processExecLog(msg);
            logger.info("exec [{} {}] cost {}ms", cmd[0], cmd[1], System.currentTimeMillis() - cur);
            return res;
        }
    }
}
